#ifndef _RENDERER_H
#define _RENDERER_H

class Level;
class Platform;
class Camera;
class Character;
class Rect;
class Slope;
struct Point2;
template <class type>
struct Quad;
struct Polygon2;
class Texture;

class GLUtesselator;
typedef class GLUtesselator GLUtriangulatorObj;

class Renderer{
public:
	static Renderer* Instance();

	enum{btnStart, btnExit};
	enum{XY=1, YZ=2, XZ=4};
	enum{DRAW_NONE=0, DRAW_GRID=1, DRAW_AXIS=2, DRAW_GEOMETRY=4, DRAW_INFO=8, DRAW_CAMERA=16};

	// set camera using camera 'c'
	void setCamera(Camera* c);

	// start 2D overlay
	void beginOverlay(float x, float y);
	// stop 2D overlay
	void endOverlay();
	// draw 'lost' message
	void drawLost();
	// draw 'won' message
	void drawWon();
	// draw 'pause' message
	void drawPause();
	// draw cross of size dx, dy at position x,y
	void drawCross(float dx, float dy, float x, float y);
	// draw menu
	void drawMenu();

	// render all + debug + auxillary info
	int renderGLScene(Level* level, Character* player, Camera* camera, unsigned int extra);
	// initialize GL renderer
	int initGL();
	// release GL renderer
	void releaseGL();
	// reset GL viewport to teh new width, height
	void reSizeGLScene(int width, int height);
	int select(float x, float y, int btn);

	// ------------------------- debug renering -------------------------
	void drawPerformance(int fps, int lms, int speed, int cycle_time);
	void drawInfo(Character* player);
	void drawLevelInfo(Level* level);
protected:
   Renderer();
private:
	static Renderer* _instance;

	unsigned int base;
	unsigned int font;
	GLUtriangulatorObj *tobj;

	// draw menu start button
	void drawStartButton();
	// draw menu exit button
	void drawExitButton();

	// render all
	void renderAll(Level* level, Character* player, Camera* c);
	// render level's geometry at level 'level' only
	void renderLevel(Level* level, int layer, Camera* cam);
	// render character's extra animation (if exists)
	void renderExtraAnimation(Character* character);
	// render slope. texture can be vertically mirrored by setting mirror to true
	void renderSlope(Slope* slope, bool mirror, float z);
	void renderQuad(Quad<Point2*>* quad, Texture* texture, bool mirror, float z);
	void renderCircle(Point2* origin, float radius, float LOD);
	void renderDisc(Point2* origin, float radius, Texture* texture, float LOD, float z);
	// render untextured rectangle at position using wireframe or filled mode
	void renderRect(Rect* rect, Point2* position, unsigned int mode);
	// render textured rectangle at position. Z -z coordinate, If the texture should be vertically mirrored- set mirror to true
	void renderRect(Rect* box, Texture* texture, Point2* position, bool mirror, float z=0);
	void renderPolygon(Polygon2* polygon, Point2* position, float z);

	// draw HUD
	void drawHUD(int ammo, int score);

	// --------------------------- work with font ------------------------
	// Delete The Font From Memory
	void killFont();
	// load font from file "Data/textures/Font.bmp"
	int loadGLFont();
	// build display lists with font's characters
	void buildFont();	
	// print ASCII string from the 'set' (0,1) at the coordinate x,y using display lists
	void glPrint(int x, int y, char *string, int set);

	// --------------------------- auxilary rendering ---------------------
	// draw player's auxillary geometry
	void renderPlayerAux(Character* player);
	// draw level's auxillary geometry
	void renderLevelAux(Level* l);
	// draw coordinate axis
	// half_len - half of the axis' length
	void drawAxis(float half_len);
	// draw 3D grid. 
	// half_len - half of the grid's length
	// res - grid's resolution
	// flag can be one of: {XY, YZ, XZ}
	void drawGrid(float half_len, float res, unsigned int flag);

	//int pick(float x, float y, unsigned int* selectBuf, int BUFSIZE);
};

#endif